package com.easy.module.system.service.impl;

import cn.hutool.core.lang.Assert;
import com.easy.framework.common.constant.Constants;
import com.easy.framework.common.utils.Func;
import com.easy.framework.common.utils.ServletUtils;
import com.easy.framework.common.utils.ip.IpUtils;
import com.easy.framework.security.model.Dept;
import com.easy.framework.security.model.LoginUser;
import com.easy.framework.security.model.Role;
import com.easy.framework.security.service.IUserDetailsService;
import com.easy.module.system.entity.SysUser;
import com.easy.module.system.service.*;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;


@Log4j2
@RequiredArgsConstructor
@Service
public class UsernamePasswordUserDetailsServiceImpl implements IUserDetailsService {

    private final ISysUserService sysUserService;

    private final ISysRoleService sysRoleService;

    private final ISysDeptService sysDeptService;

    private final ISysUserDeptService sysUserDeptService;

    private final ISysMenuService sysMenuService;

    @Override
    public boolean support(String clientId, String grantType) {
        return AuthorizationGrantType.PASSWORD.getValue().equals(grantType)
                || Constants.AUTHORIZATION_GRANT_TYPE_PASSKEY.equals(grantType);
    }

    @Override
    public int getOrder() {
        return 0;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Assert.notNull(username, "username must not be null");
        SysUser user = sysUserService.getByUsername(username);
        if (Func.isNotEmpty(user)) {
            List<Role> roles = sysRoleService.getRolesByUserId(user.getId());
            Set<String> authoritieSet = new HashSet<>();
            if (Func.isNotEmpty(roles)) {
                authoritieSet = roles.stream().map(Role::getRoleKey).collect(Collectors.toSet());
                List<Long> roleIdSet = roles.stream().map(Role::getRoleId).collect(Collectors.toList());
                Set<String> uas = sysMenuService.getUserAuthorities(user.getId(), roleIdSet);
                authoritieSet.addAll(uas);
            }
            List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList(authoritieSet.toArray(new String[authoritieSet.size()]));
            List<Dept> depts = sysUserDeptService.getDeptByUserId(user.getId());
            LoginUser loginUser = new LoginUser(user.getId(),
                    user.getUsername(),
                    user.getPassword(),
                    user.getNickname(),
                    depts, roles, authorities);
            UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
            String ip = IpUtils.getIpAddr();
            loginUser.setIp(ip);
            loginUser.setBrowser(userAgent.getBrowser().getName());
            loginUser.setOs(userAgent.getOperatingSystem().getName());
            return loginUser;
        } else {
            throw new UsernameNotFoundException("User not found");
        }
    }
}
